/*
 * @Author: reiner850593913 103234074+reiner850593913@users.noreply.github.com
 * @Date: 2022-04-08 14:54:07
 * @LastEditors: ReinerLau lk850593913@gmail.com
 * @LastEditTime: 2022-10-17 13:04:41
 * @FilePath: \robot-management-web\src\permission.js
 * @Description: 登录成功后跳转的路由权限验证
 */
import router, { asyncRoutes } from "@/router/index.js";
import { useUserStore } from "@/store/user.js";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
import { getToken } from "@/utils/auth.js";
import getPageTitle from "@/utils/get-page-title.js";
import { usePermissionStore } from "@/store/permission.js";
import cloneDeep from "lodash/cloneDeep";
import remove from "lodash/remove";

// 配置 NProgress，不显示旋转loading
NProgress.configure({ showSpinner: false });

// 不需要校验权限的白名单
const whiteList = ["/login"];

// 每次路由跳转前要进行权限验证
router.beforeEach(async (to) => {
  // 进度条开始播放
  NProgress.start();
  // 设置浏览器tab标题
  document.title = getPageTitle(to.meta.title);
  // 从 cookie 中获取 token，校验用户是否已经登录
  const hasToken = getToken();
  if (hasToken) {
    const path = await handleHasToken(to);
    return path;
  } else {
    return handleNoToken(to);
  }
});

router.afterEach(() => {
  // 进度条结束播放
  NProgress.done();
});

// 处理有 token 的情况
async function handleHasToken(to) {
  if (to.path === "/login") {
    return "/";
  } else {
    const { name, getInfo } = useUserStore();
    const { getBtnPermission } = usePermissionStore();
    const hasGetUserInfo = name;
    if (!hasGetUserInfo) {
      const { menus, roles, entrances } = await getInfo();
      await getBtnPermission();
      handleRoutes(menus, roles);
      if (roles.includes("超级管理员")) {
        return to.fullPath;
      }
      // 如果是相关角色跳转到相关页面
      if (to.path === "/" && entrances && entrances.length > 0) {
        if (router.hasRoute(entrances[0])) {
          return { name: entrances[0] };
        } else {
          return "/";
        }
      }
      // 防止刷新页面之后刚动态添加完路由后要重定向到新增的路由，否则还是空白页面
      return to.fullPath;
    } else {
      return true;
    }
  }
}
// 处理没有 token 的情况
function handleNoToken(to) {
  if (!whiteList.includes(to.path)) {
    return "/login";
  }
  return true;
}

let has;
/**
 * @description: 动态生成路由
 * @return {*}
 */
function handleRoutes(menus, roles) {
  if (roles.includes("超级管理员")) {
    // 如果是超级管理员，不分权限
    asyncRoutes.forEach((route) => {
      router.addRoute(route);
    });
  } else {
    const cloneRoutes = cloneDeep(asyncRoutes);
    menus.forEach((menu) => {
      has = false;
      findRoute(cloneRoutes, menu);
    });
    filterRoute(cloneRoutes);
    cloneRoutes.forEach((route) => {
      router.addRoute(route);
    });
  }
}

/**
 * @description: 找到有权限的路由，标记 show 为 true
 * @param {*} routes
 * @param {*} menu
 * @return {*}
 */
function findRoute(routes, menu) {
  if (has) return;
  routes.forEach((route) => {
    if (has) return;
    if (route.name === menu.name) {
      has = true;
      route.meta.show = true;
      return;
    }
    if (route.children) {
      findRoute(route.children, menu);
    }
  });
}

/**
 * @description: 根据 show 判断是否移除出没有权限的路由
 * @param {*} routes
 * @return {*}
 */
function filterRoute(routes) {
  remove(routes, (route) => !route.meta.show && !route.children);
  routes.forEach((route) => {
    if (route.children) {
      filterRoute(route.children);
    }
  });
  // 移除没有子路由的父路由
  remove(routes, (route) => route.children && route.children.length === 0);
}
